<?php
namespace Api;
use Controller\MchOrder;
use Controller\Member;
use Kuyuan\WqCore\api\Api;
use Kuyuan\WqCore\util\Util;
use Kuyuan\WqCore\wx\Pay;
use Kuyuan\WqCore\util\DB;

/**
 * 发红包
 * Class SendRed
 * @package Api
 */
class SendRed extends Api
{
    private $Red = null;
    private $Member = null;

    // 接收的红包数据
    private $_data = array();
    // 红包id
    private $_red_id = 0;

    public function __construct()
    {
        parent::__construct();
        $this->Red = $this->newController("Red");
        if(isset($this->_gpc["data"])) $this->_data = $this->_gpc["data"];
        if(isset($this->_gpc["red_id"])) $this->_red_id = $this->_gpc["red_id"];
    }

    /**
     * 发红包
     */
    public function index()
    {
        Util::appointPost();
        // 验证红包金额是否满足最低红包金额限制
        $_check_result = $this->check();
        if($_check_result !== true) {
            Util::returns((array)$_check_result);
        }

        // 新增红包
        $_result = array();
        if($this->_red_id = $this->Red->add($this->_data)) {
            $_pay_result = $this->pay();
            if($_pay_result) {
                if($_pay_result === true) {
                    $_result = array("code"=>0,"data"=>$this->_red_id);
                } else {
                    $_result = array("code"=>0,"data"=>$this->_red_id,"pay_params"=>$_pay_result);
                }
            } else {
                $_result = array("code"=>104);
            }
        } else {
            $_result = array("code"=>103);
        }
        Util::returns($_result);
    }

    /**
     * 发红包之前验证
     */
    private function check()
    {
        $_check_result = $this->checkLowRedMoney();
        if($_check_result !== true) {
            return $_check_result;
        }
        return true;
    }

    /**
     * 验证红包最低总额
     */
    private function checkLowRedMoney()
    {
        $Setting = $this->newController("Setting");
        $_setting = $Setting->find();
        if($_setting["low_red_money"] > 0) {
            $_red_total = $this->_data["pay"] - $this->_data["charge"];
            if($_red_total < $_setting["low_red_money"]) {
                return array("code"=>702,"err_msg"=>"红包总额不能低于".$_setting["low_red_money"]."元[s]");
            }
        }
        return true;
    }

    /**
     * 支付发红包金额，并且返回支付参数
     */
    private function pay()
    {
        $SettingFinance = new \Controller\SettingFinance();
        $_setting_finance = $SettingFinance->find();
        $this->Member = new Member();
        // 判断是否支持余额发红包,并且判断用户余额是否足够
        if($_setting_finance["balance_send"]
            &&
            $this->Member->finance() >= $this->_data["pay"]
        ) {
            // 用户余额足够，扣除用户余额
            return $this->expend();
        } else {
            // 获取微信支付参数
            return $this->getWxPayParams();
        }
    }

    /**
     * 扣除余额
     */
    private function expend()
    {
        DB::begin();
        try{
            $this->Member->financeHandle($this->_data["pay"],false);
            $this->Red->edit($this->_red_id,array("status"=>2,"pay_type"=>1));
            DB::commit();
        }catch (\PDOException $e) {
            DB::back();
            return false;
        }
        return true;
    }

    /**
     * 获取微信支付参数
     */
    private function getWxPayParams()
    {
        $MchOrder = new MchOrder();
        $Setting = new \Controller\Setting();
        $_setting = $Setting->find();
        $_order = [
            'out_trade_no' => $MchOrder->create($this->_data["pay"],$this->_red_id),
            'total_fee' => KUYUAN_DEBUG ? 101 : $this->_data["pay"]*100,
            'body' => $_setting["app_name"]."发红包",
            'openid' => $this->Member->uidToOpenid(),
        ];
        return \Yansongda\Pay\Pay::wechat(Pay::config())->mp($_order);
    }

    /**
     * 发红包微信支付成功
     */
    public function wxPaySuccess()
    {
        if(!$this->checkWxPay()) {
            Util::returns(array("code"=>105));
        }
        $Mch = $this->newController("MchOrder");
        DB::begin();
        try{
            $Mch->edit($this->_red_id,array("status"=>2));
            $this->Red->edit($this->_red_id,array("status"=>2,"pay_type"=>2));
            $_result = array("code"=>0);
            DB::commit();
        }catch (\PDOException $e) {
            $_result = array("code"=>103);
            DB::commit();
        }
        Util::returns($_result);
    }

    /**
     * 验证微信支付
     */
    private function checkWxPay()
    {
        $Mch = $this->newController("MchOrder");
        $_mch_order = $Mch->find($this->_red_id);
        // 查询微信商户订单
        $_result = \Yansongda\Pay\Pay::wechat(Pay::config())->find($_mch_order["order_id"]);
        // 微信商户订单支付状态是否成功
        if($_result->trade_state != "SUCCESS") {
            $this->wxPayAbnormal($_mch_order["order_id"]);
            return false;
        }
        // 微信商户支付金额和本地订单金额是否一致（红包支付金额+本地微信支付订单金额+微信商户支付金额是否一致）
        // 判断是否为沙箱测试模式
        if($_result->device_info != "sandbox") {
            if((floor($_result->cash_fee) != floor($_mch_order["money"]*100))) {
                // 订单异常
                $this->wxPayAbnormal($_mch_order["order_id"]);
                return false;
            }
            if(floor($_result->cash_fee) != floor($this->Red->value($this->_red_id,"pay")*100)) {
                // 红包金额异常
                $this->wxPayAbnormal($_mch_order["order_id"]);
                return false;
            }
        }
        return true;
    }

    /**
     * 微信支付异常处理
     * @param int $_order_id 订单id
     */
    private function wxPayAbnormal($_order_id)
    {
        $Mch = $this->newController("MchOrder");
        $Mch->edit($this->_red_id,array("status"=>8));
        $this->Red->edit($this->_red_id,array("status"=>8));
    }

    /**
     * 微信支付失败
     * @param int $_red_id 红包id
     */
    public function wxPayFail()
    {
        Util::appointPost();
        $Mch = $this->newController("MchOrder");
        DB::begin();
        try {
            $Mch->edit($this->_red_id,array("status"=>6));
            $this->Red->edit($this->_red_id,array("status"=>6));
            $_result = array("code"=>0);
            DB::commit();
        } catch (\PDOException $e) {
            $_result = array("code"=>105);
            DB::back();
        }
        Util::returns($_result);
    }
}